import { EntityInfo, EntityPartType } from '@amcax/web-render';
import PickManager from './PickManager';
import { widgetManager } from '@/common/managers';
import { EntOtpMod, HandleType } from './type';
import { EntityTitleMap } from '@/common/types/command/types';
import { labelManager } from '@/common/preview';

export enum EType {
  itself = 'itself', // 选择实体
  fromPoint = 'fromPoint', // 根据某个类型获取实体
}
const types = [
  EntityPartType.face,
  EntityPartType.line,
  EntityPartType.spatialLine,
  EntityPartType.singleLine,
  EntityPartType.doubleLine,
  EntityPartType.tripleLine,
];

const hasLabelEntType = [EntityPartType.face, EntityPartType.element];
export class EntSelect {
  private shiftSelectEnt: Set<string> = new Set(); // 可以被shif hover 选中的实体点
  private obtainMode: EType = EType.itself; // 获取类型
  private pointEnts: Set<string> = new Set();
  constructor(private parent: PickManager) {}
  setShiftSelectEnt(value?: EntityInfo[]) {
    this.shiftSelectEnt.clear();
    value?.forEach((item) => {
      this.shiftSelectEnt.add(this.parent.makeId(item));
    });
  }
  setObtainMode(value: EType) {
    this.obtainMode = value;
    this.setHitAndPickType();
  }
  get currentPickType() {
    return this.parent.currentPickType;
  }
  get selectedEnts() {
    return this.parent.getPickSelect().selectedEntMap;
  }
  get pickMode() {
    return this.parent.pickMode;
  }
  setHitAndPickType() {
    if (this.currentPickType) {
      let tip = '';
      switch (this.obtainMode) {
        case EType.itself: {
          tip = '选择' + EntityTitleMap[this.currentPickType];
          this.parent.pickType = this.currentPickType;
          break;
        }
        case EType.fromPoint: {
          tip = '通过节点选择实体';
          if (types.includes(this.currentPickType)) {
            this.parent.pickType = EntityPartType.point;
          } else {
            this.currentPickType === EntityPartType.element
              ? (this.parent.pickType = EntityPartType.node)
              : this.currentPickType === EntityPartType.node
                ? (this.parent.pickType = EntityPartType.element)
                : (this.parent.pickType = this.currentPickType);
          }
        }
      }
      widgetManager.hint(tip);
    }
  }
  /**
   * 处理实体的选择或悬停操作，尤其针对点类型的实体，会查找相关实体并进行相应操作。
   */
  public handle(
    e: EntityInfo, // 实体信息对象，包含实体的相关信息。
    state = true, // 是否选中
    key = EntOtpMod.SELECTED, // 操作模式， 选中或者悬停
    shift = false, // 是否shift
  ) {
    this.setLabel(e);
    if (
      [EntityPartType.point, EntityPartType.solid].includes(
        this.currentPickType,
      )
    ) {
      return [e];
    } else if (e?.type === EntityPartType.point) {
      const ents = this.parent.getEntByOtherEnt(e);
      const temp = this.pointRelevantEnt({ ents, state, key, shift });
      if (key === EntOtpMod.SELECTED) {
        this.parent.setSelectOrHover(e, false, key);
      }
      this.resetGetEntPoint();
      return temp.filter((it) => it.type === this.currentPickType);
    } else if (e?.type === EntityPartType.element) {
      //
    }
    return [e];
  }
  setLabel(e: EntityInfo) {
    const hasType = hasLabelEntType.includes(this.currentPickType); // pick 类型是否在可显示label类型中
    if (this.parent.isPick && hasType && this.obtainMode === EType.itself) {
      this.parent.setUpdataLabel(
        e,
        EntityPartType.face === e?.type
          ? 'FACE: ' + e?.dxid + '_' + e?.idx
          : 'ELEMENT: ' + e?.idx,
      );
    }
  }
  // 鼠标按下事件处理函数，用于处理实体的选择或取消选择操作。
  onMouseDown(e: EntityInfo, selected?: boolean) {
    const resData = this.handle(e, selected);
    if (selected) {
      this.pointEnts.add(this.parent.makeId(e));
      this.parent.getPickSelect().addPickInfos(resData);
    } else {
      this.pointEnts.delete(this.parent.makeId(e));
      const points = this.getPointByEnt(resData);
      // pointEnts用于记录选中的实体,  用于 onBeforeHovered 使用
      points.forEach((item) => {
        // 如果取消选中的实体关联的点在pointEnts中， 将其从pointEnts中删除
        this.pointEnts.has(this.parent.makeId(item)) &&
          this.pointEnts.delete(this.parent.makeId(item));
      });
      this.parent.getPickSelect().removePickInfos(resData);
      this.resetGetEntPoint();
    }
    labelManager().removeCss2DLabel();
    return resData;
  }
  onBeforeHovered = (e: EntityInfo, shift?: boolean) => {
    const id = this.parent.makeId(e);
    if (shift) {
      return this.shiftSelectEnt.has(id);
    } else {
      return this.pointEnts.has(id);
    }
  };
  /**
   * 重置获取实体点的方法。
   * 遍历 `selectedEnts` 对象中的所有实体，查找与这些实体相关的点，并将这些点添加到 `shiftSelectEnt` 数组中。
   */
  resetGetEntPoint() {
    this.setShiftSelectEnt(
      this.getPointByEnt(Array.from(this.selectedEnts.values())),
    );
  }
  getPointByEnt(ents: EntityInfo[]) {
    const points: EntityInfo[] = [];
    ents.forEach((item) => {
      const point = this.parent.getEntByOtherEnt(item, EntityPartType.point);
      points.push(...point);
    });
    return points;
  }
  pointRelevantEnt({ ents, state, key, shift }: HandleType) {
    const isVisibleEnt = this.formatByEntType(ents);
    const temp = []; // 存储相关实体信息的数组
    ents.forEach((item) => {
      if (
        this.parent.banHoverEnt.some((e) => this.parent.isEntEqual(e, item)) ||
        !isVisibleEnt[item.type].includes(item.idx)
      ) {
        return;
      }
      // 判断是否已经选中了该实体
      const hasSelected = this.selectedEnts.has(this.parent.makeId(item));
      if (!hasSelected || !state) {
        // 如果是点击操作，将其添加到选中实体数组中，
        key === EntOtpMod.SELECTED && temp.push(item);
        // 排除(当shift且没有选中的实体进行悬停的操作)
        if (!(key === EntOtpMod.HOVER && shift && !hasSelected)) {
          this.parent.hoverSelected(item, state, key);
        }
      } else if (shift) {
        if (item.type === this.currentPickType) {
          this.parent.hoverSelected(item, state, key);
        }
      }
    });
    return temp;
  }
  /**
   * @description 把过滤掉visible为false的实体
   * @param ents 实体数组
   * */
  formatByEntType(ents: EntityInfo[]) {
    const resEnts = { line: [], face: [], element: [] };
    ents.forEach((item) => {
      if (item.type === EntityPartType.line) {
        resEnts.line.push(item.idx);
      } else if (item.type === EntityPartType.face) {
        resEnts.face.push(item.idx);
      }
    });
    return resEnts;
  }
  release() {
    this.shiftSelectEnt.clear();
    this.pointEnts.clear();
  }
}
